#include <iostream>
#include <new>


/*
需要实现PushBack PopBack EmplaceBack
迭代器？

迭代器通常具有以下操作：

1. 前置递增操作符 (++it)：将迭代器向前移动到下一个元素，并返回移动后的迭代器。
2. 后置递增操作符 (it++)：将迭代器向前移动到下一个元素，并返回移动前的迭代器的副本。
3. 前置递减操作符 (--it)：将迭代器向后移动到上一个元素，并返回移动后的迭代器。
4. 后置递减操作符 (it--)：将迭代器向后移动到上一个元素，并返回移动前的迭代器的副本。
5. 解引用操作符 (*it)：返回迭代器当前位置的元素的引用。
6. 成员访问操作符 (it->member)：返回迭代器当前位置的元素的成员的引用。
7. 下标操作符 (it[index])：返回迭代器当前位置加上索引的元素的引用。
8. 相等操作符 (it1 == it2)：比较两个迭代器是否指向相同的位置。
9. 不等操作符 (it1 != it2)：比较两个迭代器是否指向不同的位置。
*/

template <typename Vector>
class VectorIterator
{
public:
    /*
     //typename关键字是必要的，以表明Vector::ValueType是一个类型如果没有typename关键字，编译器将无法确定Vector::ValueType是类型还是值，并且会生成编译错误
    */
    using ValueType = typename Vector::ValueType;
    using PointerType = ValueType *;
    using ReferenceType = ValueType &;

public:
    VectorIterator(PointerType ptr) : m_Ptr(ptr) {}

    // 前置递增操作符
    VectorIterator &operator++()
    {
        m_Ptr++;
        return *this;
    }

    // 后置递增操作符
    VectorIterator operator++(int)
    {
        VectorIterator iterator = *this; // 创建临时对象，迭代器的副本
        ++(*this);                       // 调用前置递增操作符，将当前迭代器自增到下一个位置
        return iterator;                 // 返回保存的临时迭代器对象
    }

    // 前置递减操作符
    VectorIterator &operator--()
    {
        m_Ptr--;
        return *this;
    }

/*

VectorIterator it = ...;
--it;
--it;

如果预减量操作符没有返回引用，则在迭代器的临时副本上执行第二次减量操作，原始迭代器将保持不变。然而，通过返回一个引用，第二个自减操作直接修改了原来的迭代器。
迭代器it需要改变
*/
    // 后置递减操作符
    VectorIterator operator--(int)
    {
        VectorIterator iterator = *this;
        --(*this);
        return iterator;
    }

    ReferenceType operator[](int index)
    {
        return *(m_Ptr + index);
    }

    PointerType operator->()
    {
        return m_Ptr;
    }

    ReferenceType operator*()
    {
        return *m_Ptr;
    }

    bool operator==(const VectorIterator &other) const
    {
        return m_Ptr == other.m_Ptr;
    }

    /*第二个操作符==函数递归地调用自己，导致无限循环，最终导致堆栈溢出错误。这是因为operator==函数是根据自身定义的，并且将继续调用自身，直到堆栈溢出。

    bool operator==(const VectorIterator& other) const
    {
        return *this == other;
    }
    */

    bool operator!=(const VectorIterator &other) const
    {
        return !(*this == other);
    }

private:
    PointerType m_Ptr;
};


/*
std::vector是C++标准库中的一个常用容器，提供了以下常见接口：

1. 构造函数：vector()、vector(size_type count)、vector(size_type count, const T& value)、vector(InputIt first, InputIt last)等。
2. 大小和容量相关：size()、empty()、capacity()、reserve(size_type new_cap)、shrink_to_fit()等。
3. 元素访问：operator[]、at()、front()、back()等。
4. 修改容器：push_back(const T& value)、push_back(T&& value)、emplace_back(Args&&... args)、pop_back()、insert()、erase()、clear()等。
5. 迭代器相关：begin()、end()、rbegin()、rend()等。
6. 容器操作：swap()、resize()、assign()等。
7. 比较操作：operator==、operator!=、operator<、operator<=、operator>、operator>=等。
*/


template <typename T>
class Vector
{
public:
    using ValueType = T;
    using Iterator = VectorIterator<Vector<T>>;

public:
    Vector()
    {
        ReAlloc(2);
    }

    ~Vector()
    {
        Clear(); // 进行调用所有容器内对象的析构函数
        // delete[] m_Data;
        ::operator delete(m_Data, m_Capacity * sizeof(T)); // 这不会调用任何析构函数
    }

    void PushBack(const T &value)
    {
       std::cout << "PushBack const T&" << std::endl;
        if (m_Size >= m_Capacity)
        {
            ReAlloc(m_Capacity + m_Capacity / 2);
        }
        new(&m_Data[m_Size]) T(value); // 使用拷贝构造函数初始化对象
        //m_Data[m_Size] = value;
        m_Size++;
    }

    void PushBack(T &&value)
    {
        std::cout << "PushBack T&&" << std::endl;
        if (m_Size >= m_Capacity)
        {
            ReAlloc(m_Capacity + m_Capacity / 2);
        }
        // 你不能在这里使用赋值操作符(无论是移动还是复制)，因为m_Data是未初始化的内存-它不是类型T的对象
        // m_Data[m_Size] = std::move(value);
        new(&m_Data[m_Size]) T(std::move(value)); // 使用移动构造函数初始化对象
        m_Size++;
    }

    template <typename... Args>
    T &EmplaceBack(Args &&...args) // 注意返回的是引用
    {
        if (m_Size >= m_Capacity)
            ReAlloc(m_Capacity + m_Capacity / 2);

        // 已存在的内存中 适当的位置进行构建事物 placement new
        new (&m_Data[m_Size]) T(std::forward<Args>(args)...);
        // 下面代码会构造对象 进行移动赋值
        // m_Data[m_Size] = T(std::forward<Args>(args)...); //构造T对象， std::forward<Args>(args)...进行解压缩 这些参数
        return m_Data[m_Size++];
    }

    void PopBack()
    {
        if (m_Size > 0)
        {
            m_Size--;
            m_Data[m_Size].~T();
        }
    }

    void Clear()
    {
        for (size_t i = 0; i < m_Size; i++)
        {
            m_Data[i].~T();
        }

        m_Size = 0;
    }

    // 返回一个可修改的引用，允许通过索引访问和修改Vector中的元素
    T &operator[](size_t index)
    {
        if (index >= m_Size)
        {
            // assert
        }
        return m_Data[index];
    }

    const T &operator[](size_t index) const
    {
        if (index >= m_Size)
        {
            // assert
            std::out_of_range("index out of size");
        }
        return m_Data[index];
    }

    size_t Size() const { return m_Size; }

    Iterator end()
    {
        return Iterator(m_Data + m_Size);
    }

    Iterator begin()
    {
        return Iterator(m_Data);
    }

private:
    void ReAlloc(size_t newCapacity)
    {
        // 1. allocate a new block of memory
        // 2. copy/move old elements to new block
        // 3. delete

        // T* newBlock = new T[newCapacity];
        // 改变内存分配方式，防止重复析构
        // 这里也没有必要调用构造函数，要做的只是分配足够的内存
        T *newBlock = (T *)::operator new(newCapacity * sizeof(T));

        // 增大或缩小我们的vector
        if (newCapacity < m_Size) // 重新分配的大小 < 原来的大小，注意内存分配的大小是否溢出
        {
            m_Size = newCapacity;
        }
        for (size_t i = 0; i < m_Size; i++)
        {
            // 如果没有这种类型的移动构造函数，就 复制
            // 重新分配内存时，也进行移动
            /*
            使用std::string 会崩溃
            你不能在这里使用赋值操作符(无论是移动还是复制)，因为newBlock[i]是未初始化的内存-它不是类型T的对象，
            通过调用operator=(再次移动或不移动)，你把它当作类型T的对象。因此，你应该再次使用放置new，
            因此将该行更改为:new (&newData[i]) T(std::move(m_Data[i]))
            */
            // newBlock[i] = std::move(m_Data[i]); //不使用memcpy的原因是：对于自定义数据，需要调用相应的拷贝赋值函数
            new (&newBlock[i]) T(std::move(m_Data[i]));
            // newBlock[i] = m_Data[i];
        }

        // 删除old数据
        // 改变内存释放方式，防止重复析构
        // delete[] m_Data;
        // 调用容器内对象析构函数
        for (size_t i = 0; i < m_Size; i++)
            m_Data[i].~T(); // 不能调用Clear()函数，会把m_Size = 0

        // 再释放容器old分配的空间
        ::operator delete(m_Data, m_Capacity * sizeof(T));
        m_Data = newBlock;
        m_Capacity = newCapacity;
    }

private:
    T *m_Data = nullptr;
    size_t m_Size = 0;
    size_t m_Capacity = 0;
};

struct Object
{
    float x = 0.0f, y = 0.0f, z = 0.0f;
    int *m_MemoryBlock = nullptr;

    Object() { m_MemoryBlock = new int[5]; }
    Object(float scalar) : x(scalar), y(scalar), z(scalar)
    {
        m_MemoryBlock = new int[5];
    }
    Object(float x, float y, float z) : x(x), y(y), z(z)
    {
        m_MemoryBlock = new int[5];
    }

    Object(const Object &other) = delete;
    // Object(const Object& other) //复制构造函数
    // : x(other.x), y(other.y), z(other.z)
    // {
    //     std::cout << "Copy!" << std::endl;
    // }

    Object(Object &&other) // 针对移动构造，移动赋值，不要加const
        : x(other.x), y(other.y), z(other.z)
    {
        m_MemoryBlock = other.m_MemoryBlock;
        other.m_MemoryBlock = nullptr;

        std::cout << "Move!" << std::endl;
    }
    ~Object()
    {
        std::cout << "Destory!" << std::endl;
        delete[] m_MemoryBlock;
    }

    Object &operator=(const Object &other) = delete;
    // Object& operator=(const Object& other) // 拷贝赋值
    // {
    //     std::cout << "Copy = !" << std::endl;
    //     x = other.x;
    //     y = other.y;
    //     z = other.z;

    //     return *this;
    // }

    Object &operator=(Object &&other) // 移动赋值
    {
        m_MemoryBlock = other.m_MemoryBlock;
        other.m_MemoryBlock = nullptr;

        std::cout << "Move = !" << std::endl;
        x = other.x;
        y = other.y;
        z = other.z;

        return *this;
    }
};

template <typename T>
void PrintVector(const Vector<T> &vector)
{
    for (size_t i = 0; i < vector.Size(); i++)
    {
        std::cout << vector[i] << std::endl;
    }

    std::cout << "------------------" << std::endl;
}

template <>
void PrintVector(const Vector<Object> &vector)
{
    for (size_t i = 0; i < vector.Size(); i++)
    {
        std::cout << vector[i].x << vector[i].y << vector[i].z << std::endl;
    }

    std::cout << "------------------" << std::endl;
}

int main()
{
 /*
    Vector<std::string> vec;
    vec.EmplaceBack("caoxiansheng");
    vec.EmplaceBack("c++");
    vec.EmplaceBack("Today");
    vec.EmplaceBack("is");
    vec.EmplaceBack("Tursday");
    std::string tm = "test";
    vec.PushBack(tm);
    vec.PushBack("hhaha");

    std::cout << "vec size(): " << vec.Size() << std::endl;
    // PrintVector(vec);

    for (int i = 0; i < vec.Size(); i++)
    {
        std::cout << vec[i] << std::endl;
    }

    for (auto &value : vec)
    {
        std::cout << value << std::endl;
    }

    for (Vector<std::string>::Iterator it = vec.begin(); it != vec.end(); it++)
    {
        std::cout << *it << std::endl;
    }
*/
      {
         Vector<Object> data;
         data.PushBack(Object(1.0f)); //实际不会原地构造对象，只是将到移动到data内部拥有的数据储存中，在我的数据块中就地构建
         data.PushBack(Object(2, 3, 4));
 //       data.PushBack(Object()); //元素个数2，3，4，6依次扩容

        data.EmplaceBack(1.0f); //接受一个参数列表
        data.EmplaceBack(2, 3, 4);
        PrintVector(data);
        data.EmplaceBack(); //若此时进行vector增量，则扩容2+1，再进行3次移动拷贝
         PrintVector(data);
    /*
    bird方式，在调用PopBack之前正常，在调用PopBack（）会调用析构函数，在Vector<Object> data超出作用域，又调用~Vector() 进行原有方式析构delete[] m_Data,造成double free;
    所以需要更改原因内存分配和释放方式。
    */
     //    data.PopBack();
     //    data.PopBack();
     //    PrintVector(data);
     //   data.EmplaceBack(1, 7, 9);
     //   data.EmplaceBack(5, 2, 0);
     //   data.EmplaceBack(9, 1, 1);
     //   PrintVector(data);
      //  data.Clear();
      //  PrintVector(data);
      }
}
